home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Python1.4_Source / Lib / mailcap.py < prev    next >
Text File  |  1998-06-24  |  5KB  |  224 lines

  1. # Mailcap file handling.  See RFC 1524.
  2.  
  3. import os
  4. import string
  5. import tempfile
  6.  
  7.  
  8. # Part 1: top-level interface.
  9.  
  10. def getcaps():
  11.     caps = {}
  12.     for mailcap in listmailcapfiles():
  13.     try:
  14.         fp = open(mailcap, 'r')
  15.     except:
  16.         continue
  17.     morecaps = readmailcapfile(fp)
  18.     fp.close()
  19.     for key in morecaps.keys():
  20.         if not caps.has_key(key):
  21.         caps[key] = morecaps[key]
  22.         else:
  23.         caps[key] = caps[key] + morecaps[key]
  24.     return caps
  25.  
  26. def listmailcapfiles():
  27.     # XXX Actually, this is Unix-specific
  28.     if os.environ.has_key('MAILCAPS'):
  29.     str = os.environ['MAILCAPS']
  30.     mailcaps = string.splitfields(str, ':')
  31.     else:
  32.     if os.environ.has_key('HOME'):
  33.         home = os.environ['HOME']
  34.     else:
  35.         # Don't bother with getpwuid()
  36.         home = '.' # Last resort
  37.     mailcaps = [home + '/.mailcap', '/etc/mailcap',
  38.         '/usr/etc/mailcap', '/usr/local/etc/mailcap']
  39.     return mailcaps
  40.  
  41.  
  42. # Part 2: the parser.
  43.  
  44. def readmailcapfile(fp):
  45.     caps = {}
  46.     while 1:
  47.     line = fp.readline()
  48.     if not line: break
  49.     # Ignore comments and blank lines
  50.     if line[0] == '#' or string.strip(line) == '':
  51.         continue
  52.     nextline = line
  53.     # Join continuation lines
  54.     while nextline[-2:] == '\\\n':
  55.         nextline = fp.readline()
  56.         if not nextline: nextline = '\n'
  57.         line = line[:-2] + nextline
  58.     # Parse the line
  59.     key, fields = parseline(line)
  60.     if not (key and fields):
  61.         continue
  62.     # Normalize the key
  63.     types = string.splitfields(key, '/')
  64.     for j in range(len(types)):
  65.         types[j] = string.strip(types[j])
  66.     key = string.lower(string.joinfields(types, '/'))
  67.     # Update the database
  68.     if caps.has_key(key):
  69.         caps[key].append(fields)
  70.     else:
  71.         caps[key] = [fields]
  72.     return caps
  73.  
  74. def parseline(line):
  75.     fields = []
  76.     i, n = 0, len(line)
  77.     while i < n:
  78.     field, i = parsefield(line, i, n)
  79.     fields.append(field)
  80.     i = i+1 # Skip semicolon
  81.     if len(fields) < 2:
  82.     return None, None
  83.     key, view, rest = fields[0], fields[1], fields[2:]
  84.     fields = {'view': view}
  85.     for field in rest:
  86.     i = string.find(field, '=')
  87.     if i < 0:
  88.         fkey = field
  89.         fvalue = ""
  90.     else:
  91.         fkey = string.strip(field[:i])
  92.         fvalue = string.strip(field[i+1:])
  93.     if fields.has_key(fkey):
  94.         # Ignore it
  95.         pass
  96.     else:
  97.         fields[fkey] = fvalue
  98.     return key, fields
  99.  
  100. def parsefield(line, i, n):
  101.     start = i
  102.     while i < n:
  103.     c = line[i]
  104.     if c == ';':
  105.         break
  106.     elif c == '\\':
  107.         i = i+2
  108.     else:
  109.         i = i+1
  110.     return string.strip(line[start:i]), i
  111.  
  112.  
  113. # Part 3: using the database.
  114.  
  115. def findmatch(caps, type, key='view', filename="/dev/null", plist=[]):
  116.     entries = lookup(caps, type, key)
  117.     for e in entries:
  118.     if e.has_key('test'):
  119.         test = subst(e['test'], filename, plist)
  120.         if test and os.system(test) != 0:
  121.         continue
  122.     command = subst(e[key], type, filename, plist)
  123.     return command, e
  124.     return None, None
  125.  
  126. def lookup(caps, type, key=None):
  127.     entries = []
  128.     if caps.has_key(type):
  129.     entries = entries + caps[type]
  130.     types = string.splitfields(type, '/')
  131.     type = types[0] + '/*'
  132.     if caps.has_key(type):
  133.     entries = entries + caps[type]
  134.     if key is not None:
  135.     entries = filter(lambda e, key=key: e.has_key(key), entries)
  136.     return entries
  137.  
  138. def subst(field, type, filename, plist=[]):
  139.     # XXX Actually, this is Unix-specific
  140.     res = ''
  141.     i, n = 0, len(field)
  142.     while i < n:
  143.     c = field[i]; i = i+1
  144.     if c <> '%':
  145.         if c == '\\':
  146.         c = field[i:i+1]; i = i+1
  147.         res = res + c
  148.     else:
  149.         c = field[i]; i = i+1
  150.         if c == '%':
  151.         res = res + c
  152.         elif c == 's':
  153.         res = res + filename
  154.         elif c == 't':
  155.         res = res + type
  156.         elif c == '{':
  157.         start = i
  158.         while i < n and field[i] <> '}':
  159.             i = i+1
  160.         name = field[start:i]
  161.         i = i+1
  162.         res = res + findparam(name, plist)
  163.         # XXX To do:
  164.         # %n == number of parts if type is multipart/*
  165.         # %F == list of alternating type and filename for parts
  166.         else:
  167.         res = res + '%' + c
  168.     return res
  169.  
  170. def findparam(name, plist):
  171.     name = string.lower(name) + '='
  172.     n = len(name)
  173.     for p in plist:
  174.     if string.lower(p[:n]) == name:
  175.         return p[n:]
  176.     return ''
  177.  
  178.  
  179. # Part 4: test program.
  180.  
  181. def test():
  182.     import sys
  183.     caps = getcaps()
  184.     if not sys.argv[1:]:
  185.     show(caps)
  186.     return
  187.     for i in range(1, len(sys.argv), 2):
  188.     args = sys.argv[i:i+2]
  189.     if len(args) < 2:
  190.         print "usage: mailcap [type file] ..."
  191.         return
  192.     type = args[0]
  193.     file = args[1]
  194.     command, e = findmatch(caps, type, 'view', file)
  195.     if not command:
  196.         print "No viewer found for", type
  197.     else:
  198.         print "Executing:", command
  199.         sts = os.system(command)
  200.         if sts:
  201.         print "Exit status:", sts
  202.  
  203. def show(caps):
  204.     print "Mailcap files:"
  205.     for fn in listmailcapfiles(): print "\t" + fn
  206.     print
  207.     if not caps: caps = getcaps()
  208.     print "Mailcap entries:"
  209.     print
  210.     ckeys = caps.keys()
  211.     ckeys.sort()
  212.     for type in ckeys:
  213.     print type
  214.     entries = caps[type]
  215.     for e in entries:
  216.         keys = e.keys()
  217.         keys.sort()
  218.         for k in keys:
  219.         print "  %-15s" % k, e[k]
  220.         print
  221.  
  222. if __name__ == '__main__':
  223.     test()
  224.